package proj1;
import java.util.LinkedList;

public class State {

	public static int UID = 0;
	public int PosX[];
	public int PosY[];
	public int[][] grid;
	public int carSize[];
	public boolean carOrient[];
	public int id;
	public String step; //The step that got the agent to this state
	public Tile[] tiles;
	public boolean UPLEFT = true, RIGHTDOWN = false;
	

	public State(int[][] grid, boolean orient[], int size[], int PosX[],
			int PosY[], String step) {
		this.id = UID++;
		this.grid = grid;
		this.carOrient = orient;
		this.carSize = size;
		this.PosX = PosX;
		this.PosY = PosY;
		this.step = step;
	}
	
	public State(int[][] g, Tile[] t, String s){
		this.id = UID++;
		grid = g;
		tiles = t;
		step = s;
	}
	
	

	/**
	 * function that moves a tile and return a state where the tile has been moved
	 * @param t tile to move
	 * @param upLeft a boolean that depending on the orientation will will attempt to move the tile left or up if true, and down or right if false
	 * @param visualize print the trace
	 * @return a new state where the tile was moved or null if it wasn't
	 */
	public State move(Tile t, boolean upLeft, boolean visualize){
		Tile newTile = new Tile(t);
		int[][] newGrid = new int[6][6];
		Tile[] newTiles = new Tile[tiles.length];
		String dir = "";
		int i = t.id;
		
		for(int k=0;k<tiles.length;k++){
			newTiles[k]=tiles[k];
		}
		
		for(int k=0;k<grid.length;k++){
			for(int j=0;j<grid[k].length;j++){
				newGrid[k][j]=grid[k][j];
			}
		}
		
		//System.out.print("tile "+i);
		if(!t.orientation){ //horizontal tile
			if(upLeft){//move left
				if (!(t.y - 1 > -1  && grid[t.x][t.y - 1] == -1)) {// left
					if(visualize)
					System.out.println(" can't move tile "+i+" left");
					return null;
				}
				
				newGrid[t.x][t.y - 1] = i;
				newGrid[t.x][t.y + 1] = -1;
				newTile.y--;
				dir = "move tile "+i+" left";
			} else {//move right
				if (!(t.y + t.size < 6 && grid[t.x][t.y + t.size] == -1)) {// right
					if(visualize)
					System.out.println("can't move tile "+i+" right");
					return null;
				}
				
				newGrid[t.x][t.y] = -1;
				newGrid[t.x][t.y + t.size] = i;
				newTile.y++;
				
				dir = "move tile "+i+" right";
			}
			//System.out.println(" move horizontal change y from "+t.y+" to "+newTile.y);
		} else { //vertical tile
			if(upLeft){//move up
				if (!(t.x - 1 > -1 &&  grid[t.x - 1][t.y] == -1)) {// up
					if(visualize)
					System.out.println(" can't move tile "+i+" up");
					return null;
				}
				newGrid[t.x - 1][t.y] = i;
				newGrid[t.x + t.size - 1][t.y] = -1;
				newTile.x--;
				
				dir = "move tile "+i+" up";
			} else {//move down
				if (!(t.x  + t.size < 6 &&grid[t.x + t.size][t.y] == -1)) {
					if(visualize)
					System.out.println(" can't move tile "+i+" down");
					return null;
				}
				
				newGrid[t.x][t.y] = -1;
				newGrid[t.x + t.size][t.y] = i;
				newTile.x++;
				
				dir = "move tile "+i+" down";
				
			}
			//System.out.println(" move vertical change x from "+t.x+" to "+newTile.x);
		}
		//System.out.println("y "+(t.y + t.size)+" x "+(t.x + t.size));
		
		newTiles[i] = newTile;
		State s =  new State(newGrid, newTiles, dir);
		//s.print();
		return s;
	}

	/**
	 * Computes all of the states immediately reachable from this state and
	 * returns them as an array of states.
	 * @param visualize whether to print the trace
	 */
	public LinkedList<State> expand(boolean visualize) {
		LinkedList<State> states = new LinkedList<State>();
		State s;
		for (Tile tile : tiles) {
			s = move(tile, true,visualize);
			if(s!=null) states.add(s);
			
			s = move(tile, false,visualize);
			if(s!=null) states.add(s);
		}
		return states;
	}
	
	/**
	 * function for computing how many blocks are in the way
	 * used by the blocking heuristic
	 * @return number of block in  the way
	 */
	public  int blocksInWay() {
		int blocksInWay=0;
		for(int i=this.tiles[0].y+1;i<this.grid[2].length;i++){
			if(this.grid[2][i]!=-1)
				blocksInWay++;
			
		}
		return blocksInWay;
	}

	/**
	 * checks if 2 states are equal
	 * @param s the state to check against
	 * @return true if the states are equal false otherwise
	 */
	public boolean equals(State s) {
	
		for(int i=0;i<grid.length;i++){
			for(int j=0;j<grid[i].length;j++){
				if(grid[i][j]!=s.grid[i][j]){
					return false;
				}
			}
		}
			

		return true;
	}
	

	/** Prints to standard output a primitive text representation of the state. */
	public void print() {
		int[][] b = this.grid;
		System.out.println(step+" in state "+this.id+" "+b);
		
		for (int i = 0; i < b.length; i++) {
			for (int j = 0; j < b[i].length; j++) {
				if (b[i][j] == -1)
					System.out.print("\t *");
				else
					System.out.print("\t " + b[i][j]);
			}
			System.out.println();
		}
	}
}
